Shader "Kayac/Skybox/Gradation" {
    Properties {
        _Axis ("Axis", Vector) = (1,1,1,1)
        [HDR] _UpColor ("UpColor", Color) = (1,1,1,1)
        [HDR] _DownColor ("DownColor", Color) = (1,1,1,1)
        [HDR] _HorizontalColor ("HorizontalColor", Color) = (1,1,1,1)
        _HorizontalPower ("HorizontalPower", Float) = 1
        [KeywordEnum(VERTEX, FRAGMENT)] _CalcMode ("CalcMode", Float) = 0
    }
    
    SubShader {
        Tags { "RenderType"="Background" "Queue"="Background" "PreviewType"="Skybox" }
        Cull Off
        ZWrite Off
        
        Pass {
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma shader_feature _CALCMODE_VERTEX _CALCMODE_FRAGMENT
            
            // For built-in pipeline
            #if !defined(SHADER_API_MOBILE) && !defined(SHADER_API_SWITCH)
                #define UNITY_SAMPLE_SCREEN_SPACE_SHADOWS
            #endif
            
            #include "UnityCG.cginc"
            
            float4 _Axis;
            float4 _UpColor;
            float4 _DownColor;
            float4 _HorizontalColor;
            float _HorizontalPower;
            
            struct VertexInput {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };
            
            struct VertexOutput {
                float4 pos : SV_POSITION;
                float3 worldPos : TEXCOORD0;
                float3 normal : TEXCOORD1;
                #if _CALCMODE_VERTEX
                    float4 color : COLOR;
                #endif
            };
            
            VertexOutput vert (VertexInput v) {
                VertexOutput o;
                // For both built-in and SRP
                o.pos = UnityObjectToClipPos(v.vertex);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
                o.normal = UnityObjectToWorldNormal(v.normal);
                
                #if _CALCMODE_VERTEX
                    // Calculate gradient in vertex shader
                    float dotValue = dot(normalize(_Axis.xyz), o.normal);
                    float verticalLerp = saturate(dotValue * 0.5 + 0.5);
                    float horizontalFactor = saturate(1.0 - abs(dotValue));
                    horizontalFactor = pow(horizontalFactor, _HorizontalPower);
                    
                    o.color = lerp(_DownColor, _UpColor, verticalLerp);
                    o.color = lerp(o.color, _HorizontalColor, horizontalFactor);
                #endif
                
                return o;
            }
            
            float4 frag (VertexOutput i) : SV_Target {
                #if _CALCMODE_FRAGMENT
                    // Calculate gradient in fragment shader for better quality
                    float3 axis = normalize(_Axis.xyz);
                    float3 worldNormal = normalize(i.normal);
                    float dotValue = dot(axis, worldNormal);
                    float verticalLerp = saturate(dotValue * 0.5 + 0.5);
                    float horizontalFactor = saturate(1.0 - abs(dotValue));
                    horizontalFactor = pow(horizontalFactor, _HorizontalPower);
                    
                    float4 color = lerp(_DownColor, _UpColor, verticalLerp);
                    color = lerp(color, _HorizontalColor, horizontalFactor);
                    return color;
                #else
                    return i.color;
                #endif
            }
            ENDHLSL
        }
    }
    Fallback Off
}